using JQData.Application.Helper;
using JQData.Core;
using JQData.Core.DataModel;
using JQData.Core.DbModel;
using JQData.Core.TushareSDK;
using Microsoft.Extensions.Caching.Distributed;
using System.Text.Json;



namespace JQData.Application.DataFetch
{
    /// <summary>
    /// 游资股票数据
    /// </summary>
    /// <param name="_hmDb"></param>
    /// <param name="_hmtDb"></param>
    /// <param name="_hmscpDb"></param>
    /// <param name="_sbDb"></param>
    /// <param name="_distributedCache"></param>
    public class HotMoneyDataFetch(
        IRepository<HotMoney> _hmDb,
        IRepository<HotMoneyTrade> _hmtDb,
        IRepository<HotMoneyStockCycleProfit> _hmscpDb,
        IRepository<StockBasic> _sbDb,
        IDistributedCache _distributedCache
        ) : DataFetchBase(_hmDb, _hmtDb, _hmscpDb, _sbDb)
    {
        public HotMoneyData Data { get; set; } = new();





        /// <summary>
        /// 加载数据
        /// </summary>
        /// <param name="hmId"></param>
        /// <param name="isCache"></param>
        /// <returns></returns>
        public async Task<HotMoneyData> GetHotMoneyData(int hmId, bool isCache = true)
        {
            var cacheKey = DataCacheManage.GetCacheKey(CacheKeyType.HotMoneyData, hmId);
            if (isCache)
            {
                var cachedData = await _distributedCache.GetStringAsync(cacheKey);
                if (!string.IsNullOrEmpty(cachedData))
                {
                    return JsonSerializer.Deserialize<HotMoneyData>(cachedData);
                }
            }





            Data = new HotMoneyData
            {
                HotMoneyId = hmId
            };

            await Load基本信息();
            await Load持仓情况();
            await Load顶部图表();

            // 随机缓存 10-20 分钟（含 10 和 20）

            //如果使用缓存，则添加缓存
            if (isCache)
            {
                await DataCacheManage.AddCache(_distributedCache, cacheKey, Data);
            }

            return Data;
        }

        public async Task Load基本信息()
        {
            Data.DbHotMoney = await _hmDb.FirstOrDefaultAsync(i => i.Id == Data.HotMoneyId);

            if (Data.DbHotMoney == null)
            {
                throw Oops.Oh("未找到游资数据");
            }

        }


        public async Task Load持仓情况()
        {
            Data.Day30 = await Get游资持仓表格(DateOnly.FromDateTime(DateTime.Now.AddDays(-30)));
            Data.Day7 = await Get游资持仓表格(DateOnly.FromDateTime(DateTime.Now.AddDays(-7)));



        }

        public async Task Load顶部图表()
        {
            // 近一月的交易
            var startDate = DateOnly.FromDateTime(DateTime.Now.AddMonths(-1));
            var endDate = DateOnly.FromDateTime(DateTime.Now);
            var trades = await _hmtDb.Where(i => i.HotMoneyId == Data.HotMoneyId)
                                     .Where(i => i.Date >= startDate && i.Date <= endDate)
                                     .ToListAsync();


            Data.TopChart.Add(await 顶部图表_持仓总额());
            Data.TopChart.Add(顶部图表_交易胜率());
            Data.TopChart.Add(顶部图表_盈利金额());
            Data.TopChart.Add(顶部图表_买入卖出());

        }




        public async Task<HotMoneyDataChart> 顶部图表_持仓总额()
        {
            var model = new HotMoneyDataChart()
            {
                Title = "持仓总额(近一月)",
                Date = [],
                Data = [],
                Value = "0",
                Type = "line"
            };

            var startDate = DateOnly.FromDateTime(DateTime.Now.AddMonths(-1));
            var endDate = DateOnly.FromDateTime(DateTime.Now);


            // 计算每日持仓额度
            var date = startDate;
            decimal total = 0;
            var buyList = Data.Day30.SelectMany(i => i.BuyInfo).ToList();
            var sellList = Data.Day30.SelectMany(i => i.SellInfo).ToList();


            while (date <= endDate)
            {
                var totalAmount = buyList.Where(i => i.Date == date)
                                   .Sum(i => i.Amount)
                                - sellList.Where(i => i.Date == date)
                                   .Sum(i => i.Amount);
                total += totalAmount;
                // 跳过周六、周日
                var dayOfWeek = date.DayOfWeek;
                if (dayOfWeek != DayOfWeek.Saturday && dayOfWeek != DayOfWeek.Sunday
                    && totalAmount == 0)
                {
                    // 记录日期和持仓额度
                    model.Date.Add(date.ToString("yyyy-MM-dd"));
                    model.Data.Add(Tools.FormatWandecimal(total));
                }
                date = date.AddDays(1);
            }

            // 替换原有赋值
            model.Value = Core.Tools.FormatWan(total);

            //
            var lastTotal = await _hmtDb.Where(i => i.HotMoneyId == Data.HotMoneyId)
                                   .Where(i => i.Date >= startDate.AddMonths(-1)
                                   && i.Date <= startDate)
                                   .SumAsync(i => i.BuyAmount - i.SellAmount);
            if (lastTotal == 0)
            {
                model.IsUp = total > 0;
                model.Chang = "∞";
            }
            else
            {
                var percent = (total - lastTotal) / Math.Abs(lastTotal) * 100;
                model.Chang = percent.ToString("F1") + "%";
                model.IsUp = percent > 0;
            }



            return model;
        }

        public HotMoneyDataChart 顶部图表_交易胜率()
        {
            var model = new HotMoneyDataChart()
            {
                Title = "交易胜率(近一月)",
                Date = [],
                Data = [],
                Value = "0",
                Type = "hide",
                Chang = null
            };

            var total = Data.Day30.Count;

            if (total == 0)
            {
                model.Value = "--";
            }
            else
            {
                model.Value = (Data.Day30.Count(i => i.IsWin) / (double)total * 100).ToString("F2") + "%";
            }


            return model; // Fix: Removed Task.FromResult and directly returned the model.
        }


        public HotMoneyDataChart 顶部图表_盈利金额()
        {
            var model = new HotMoneyDataChart()
            {
                Title = "盈利金额(近一月)",
                Date = [],
                Data = [],
                Value = "0",
                Type = "line"
            };

            var startDate = DateOnly.FromDateTime(DateTime.Now.AddMonths(-1));
            var endDate = DateOnly.FromDateTime(DateTime.Now);

            // 计算每日盈利金额
            var date = startDate;

            var dayStatsList = Data.Day30.SelectMany(i => i.StockDayStats);
            decimal lastProfit = 0;

            while (date <= endDate)
            {
                var dayStats = dayStatsList.Where(i => i.Date == date).ToList();


                // 跳过周六、周日
                var dayOfWeek = date.DayOfWeek;
                if (dayOfWeek != DayOfWeek.Saturday && dayOfWeek != DayOfWeek.Sunday)
                {
                    if (dayStats.Count > 0)
                    {
                        var dayProfit = Core.Tools.FormatWandecimal(dayStats.Sum(i => i.WinPrice));

                        lastProfit = dayProfit;

                        model.Date.Add(date.ToString("yyyy-MM-dd"));
                        model.Data.Add(dayProfit);
                    }
                }
                date = date.AddDays(1);
            }

            // 近一月总盈利
            model.Value = lastProfit.ToString("F2") + "万";



            return model;
        }



        public HotMoneyDataChart 顶部图表_买入卖出()
        {
            var model = new HotMoneyDataChart()
            {
                Title = "买入\\卖出\\净",
                Date = [],
                Data = [],
                Value = "0",
                Type = "minibar",
                Chang = null
            };


            foreach (var item in Data.DayStats)
            {
                model.Date.Add(item.Date.ToString("MM-dd"));
                model.Data.Add(item.BuyAmount);
                model.Data2.Add(item.SellAmount);
                model.Data3.Add(item.NetAmount);
            }

            var last = Data.DayStats.LastOrDefault();

            if (last != null)
            {
                model.Value = $"{Tools.FormatWandecimal(last.BuyAmount).ToString("f0")}万\\{Tools.FormatWandecimal(last.SellAmount).ToString("f0")}万\\{Tools.FormatWandecimal(last.NetAmount).ToString("f0")}万";
            }



            return model; // Fix: Removed Task.FromResult and directly returned the model.
        }








        /// <summary>
        /// 根据游资ID获取持仓表格数据
        /// </summary>
        /// <param name="startDate">开始时间</param>
        /// <returns>持仓数据</returns>
        public async Task<List<HotMoneyStockData>>
            Get游资持仓表格(DateOnly startDate)
        {
            //开始时间和结束时间

            var endDate = DateOnly.FromDateTime(DateTime.Now);


            // 查询近一月内该游资的所有交易
            var trs = await _hmtDb.Where(i => i.HotMoneyId == Data.HotMoneyId)
                                  .Where(i => i.Date >= startDate && i.Date <= endDate)
                                  .ToListAsync();

            // 按股票分组统计
            var stockGroup = trs.GroupBy(t => t.StockId);

            //需要返回的模型
            var result = new List<HotMoneyStockData>();
            foreach (var g in stockGroup)
            {
                var modelItem = await Get游资持仓表格_单只股票(g.Key, g.ToList(), startDate, endDate);
                //如果没有买入信息，则不添加到结果中
                if (modelItem.BuyInfo.Count > 0)
                {
                    result.Add(modelItem);
                }
            }

            //只计算净买入金额大于0的
            var tAmount = result.Where(i => i.NetBuyAmount > 0).Sum(i => i.NetBuyAmount);

            foreach (var item in result)
            {
                if (tAmount != 0)
                {
                    item.PositionRatio = (float)(item.NetBuyAmount / tAmount * 100);
                }
            }


            return result;
        }



        /// <summary>
        /// 
        /// </summary>
        /// <param name="stockId">股票Id</param>
        /// <param name="trades">交易信息</param>
        /// <param name="start">开始时间</param>
        /// <param name="end">结束时间</param>
        /// <returns></returns>
        private async Task<HotMoneyStockData> Get游资持仓表格_单只股票(int stockId,
            List<HotMoneyTrade> trades,
            DateOnly start, DateOnly end)
        {

            var model = new HotMoneyStockData
            {
                StockId = stockId,

                BuyInfo = [],
                SellInfo = [],
                Chart = [],
                StockDayStats = [],
                //获取股票信息
                DbStock = await _sbDb.Where(i => i.Id == stockId).FirstOrDefaultAsync()
            };
            model.StockName = model.DbStock?.Name;

            //sdk接口
            using var core = new TushareCore("d6bd5319b55741d52682b9586bca1bccd72e9649840c41760fe5eea3");
            var api = new StockApi(core);
            // 在Get游资持仓表格_单只股票方法中，将dayList倒序排列
            var dayList = (await api.GetDailyAsync(model.DbStock.TsCode, start, end))
                .OrderBy(d => d.TradeDate)
                .ToList();


            var dateGroup = trades.GroupBy(x => x.Date);

            //上一天的数据
            foreach (var day in dayList)
            {
                //给表格内的图表数据赋值
                var chartItem = new HotMoneyStockDataChartItem()
                {
                    Date = day.TradeDate.ToString("yyyy-MM-dd"),
                    Price = day.Close,
                };
                model.Chart.Add(chartItem);

                // 计算当天的持仓数据
                var dayStats = new HotMoneyStockDataDayStats()
                {
                    Date = day.TradeDate,
                    CurrentPrice = day.Close,
                    CostPrice = 0,
                    RemainingPosition = 0,
                };
                model.StockDayStats.Add(dayStats);



                var tradeList = trades.Where(i => i.Date == day.TradeDate).ToList();


                foreach (var trade in tradeList)
                {
                    var average = (day.Low + day.High) / 2;

                    // 处理每个交易记录
                    if (trade.BuyAmount > 0)
                    {
                        var vol = trade.BuyAmount / average;
                        model.BuyInfo.Add(new HotMoneyStockDataTradeItem()
                        {
                            Amount = trade.BuyAmount,
                            Vol = vol,
                            Price = average,
                            Date = trade.Date
                        });
                        chartItem.BuyVol += vol;
                        dayStats.BuyAmount += trade.BuyAmount;
                    }
                    if (trade.SellAmount > 0)
                    {
                        var vol = trade.SellAmount / average;
                        model.SellInfo.Add(new HotMoneyStockDataTradeItem()
                        {
                            Amount = trade.SellAmount,
                            Vol = vol,
                            Price = average,
                            Date = trade.Date
                        });
                        chartItem.SellVol += vol;

                        dayStats.SellAmount += trade.SellAmount;
                    }


                }

                var (averageCost, remainingShares) = StockHelper.CalculatePositionCost(model);
                dayStats.CostPrice = averageCost;
                dayStats.RemainingPosition = remainingShares;

                //给游资每天的数据赋值
                AddHotMoneyDayData(day.TradeDate, dayStats);




            }

            model.CurrentPrice = dayList.LastOrDefault()?.Close ?? 0;
            model.BuyDate = trades.Where(i => i.BuyAmount > 0)
                                        .OrderBy(i => i.Date)
                                        .Select(i => i.Date)
                                        .FirstOrDefault();

            var res = StockHelper.CalculatePositionCost(model);

            model.CostPrice = res.averageCost;

            model.RemainingPosition = res.remainingShares;

            //获取股票信息


            return model;
        }


        public void AddHotMoneyDayData(DateOnly date, HotMoneyStockDataDayStats dataDayStats)
        {

            var dayData = Data.DayStats.FirstOrDefault(i => i.Date == date);
            if (dayData == null)
            {
                dayData = new HotMoneyDataDayStats()
                {
                    Date = date,
                };
                Data.DayStats.Add(dayData);
            }
            dayData.BuyAmount += dataDayStats.BuyAmount;
            dayData.SellAmount += dataDayStats.SellAmount;

        }

    }
}
